// 版权所有2009 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package syscall

import "unsafe"

const _SYS_setgroups = SYS_SETGROUPS32

func setTimespec(sec, nsec int64) Timespec {
	return Timespec{Sec: int32(sec), Nsec: int32(nsec)}
}

func setTimeval(sec, usec int64) Timeval {
	return Timeval{Sec: int32(sec), Usec: int32(usec)}
}

// 基础系统调用通过指针写入newoffset。
// 在汇编中实现，以避免分配。
func seek(fd int, offset int64, whence int) (newoffset int64, err Errno)

func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
	newoffset, errno := seek(fd, offset, whence)
	if errno != 0 {
		return 0, errno
	}
	return newoffset, nil
}

// sys accept（s int，rsa*RawSockaddrAny，addrlen*_Socklen）（fd int，error）
// sys accept4（s int，rsa*RawSockaddrAny，addrlen*_Socklen，flags int）（fd int，error error）
// SYS getsockopt（s int，level int，name int，val unsafe.Pointer，vallen*_Socklen）（error error error）
// sysnb socket
// sys recvmsg（s int，msg*Msghdr，flags int）（错误）
// sys recvmsg（s int，msg*Msghdr，flags int）（n int，error error）
// sys sendmsg（s int，msg*Msghdr，flags int）（n int，error error）

// 64位文件系统和32位uid调用
// （新内核并不总是支持16位uid调用）
// sys Dup2（oldfd int，newfd int）（错误）
// sysnb EpollCreate（size int）（fd int，error）
// sys Fchown（fd int，uid int，gid int）（错误）=sys FCHOWN32 
// sys Fstat（fd int，stat stat t）（error error）=sys FSTAT64 
// sysnb Getegid（）（egid int）=SYS_GETEGID32 
// sysnb Geteuid（）（euid int）=SYS GETEUID32 
// sysnb Getuid（）（uid int）=SYS GETUID32 
// sys Pause（）（error error）
// sys Renameat（olddirfd int，oldpath string，newdirfd int，newpath string）（error error）
// sys sendfile（outd int，infdd int，offset*int64，count int）（writed int，err error error error）=sys SENDFILE64 
// SYS Setfsgid（gid int）（error error）=SYS_SETFSGID32 
// SYS Setfsuid（uid int）（error）=SYS SETFSUID32 
// SYS Shutdown（fd int，how int）（error error error）

// sysnb Gettimeofday（tv*Timeval）（error error）
// sysnb Time（t*Time_t）（tt Time_t，error error）

// SYS Pwrite（fd int，p[]字节，偏移量int64）（n int，error error）=SYS_PWRITE64 
// SYS Truncate（路径字符串，长度int64）（error）=SYS TRUNCATE64 
// SYS Ftruncate（fd int，长度int64）（error）=SYS（addr uintpttr，length uintpttr，prot int，flags int，fd int，pageOffset uintptpr）（xaddr uintpttr，error error）

// sys EpollWait（epfd int，events[]epolletent，msec int）（n int，error error）

func Stat(path string, stat *Stat_t) (err error) {
	return fstatat(_AT_FDCWD, path, stat, 0)
}

func Lchown(path string, uid int, gid int) (err error) {
	return Fchownat(_AT_FDCWD, path, uid, gid, _AT_SYMLINK_NOFOLLOW)
}

func Lstat(path string, stat *Stat_t) (err error) {
	return fstatat(_AT_FDCWD, path, stat, _AT_SYMLINK_NOFOLLOW)
}

func Fstatfs(fd int, buf *Statfs_t) (err error) {
	_, _, e := Syscall(SYS_FSTATFS64, uintptr(fd), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
	if e != 0 {
		err = e
	}
	return
}

func Statfs(path string, buf *Statfs_t) (err error) {
	pathp, err := BytePtrFromString(path)
	if err != nil {
		return err
	}
	_, _, e := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(pathp)), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
	if e != 0 {
		err = e
	}
	return
}

func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) {
	page := uintptr(offset / 4096)
	if offset != int64(page)*4096 {
		return 0, EINVAL
	}
	return mmap2(addr, length, prot, flags, fd, page)
}

type rlimit32 struct {
	Cur uint32
	Max uint32
}


const rlimInf32 = ^uint32(0)
const rlimInf64 = ^uint64(0)

func Getrlimit(resource int, rlim *Rlimit) (err error) {
	err = prlimit(0, resource, nil, rlim)
	if err != ENOSYS {
		return err
	}

	rl := rlimit32{}
	err = getrlimit(resource, &rl)
	if err != nil {
		return
	}

	if rl.Cur == rlimInf32 {
		rlim.Cur = rlimInf64
	} else {
		rlim.Cur = uint64(rl.Cur)
	}

	if rl.Max == rlimInf32 {
		rlim.Max = rlimInf64
	} else {
		rlim.Max = uint64(rl.Max)
	}
	return
}

// sysnb setrlimit 

func Setrlimit(resource int, rlim *Rlimit) (err error) {
	err = prlimit(0, resource, rlim, nil)
	if err != ENOSYS {
		return err
	}

	rl := rlimit32{}
	if rlim.Cur == rlimInf64 {
		rl.Cur = rlimInf32
	} else if rlim.Cur < uint64(rlimInf32) {
		rl.Cur = uint32(rlim.Cur)
	} else {
		return EINVAL
	}
	if rlim.Max == rlimInf64 {
		rl.Max = rlimInf32
	} else if rlim.Max < uint64(rlimInf32) {
		rl.Max = uint32(rlim.Max)
	} else {
		return EINVAL
	}

	return setrlimit(resource, &rl)
}

func (r *PtraceRegs) PC() uint64 { return uint64(r.Uregs[15]) }

func (r *PtraceRegs) SetPC(pc uint64) { r.Uregs[15] = uint32(pc) }

func (iov *Iovec) SetLen(length int) {
	iov.Len = uint32(length)
}

func (msghdr *Msghdr) SetControllen(length int) {
	msghdr.Controllen = uint32(length)
}

func (cmsg *Cmsghdr) SetLen(length int) {
	cmsg.Len = uint32(length)
}

func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno)
